#include <errno.h>
//
#include <machine/param.h>
#include <sys/ipc.h>
#include <sys/shm.h>
//
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
//
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <unistd.h>
//
#include <time.h>
#include <sys/time.h>
//
#include <signal.h>
//
#include <stdarg.h>
//
void *shmdata;
void *listdata;
struct timeval t0,t1;
//
struct timeval getTime()
{
  struct timeval tp;
  struct timezone tzp;
  tzp.tz_minuteswest=0;
  tzp.tz_dsttime=0;
  gettimeofday(&tp,&tzp);
  return tp;
}
//
void closeShm()
{
  t1=getTime();
  memcpy(shmdata+8+8+16,&t1,16);
  shmdt(shmdata);
}
//
void plog(FILE * s, const char * f, ...)
{
  struct timeval tp;
  char str[32];
  va_list ap;
  if(s==NULL) return;
  tp=getTime();
  strcpy(str,asctime(localtime(&tp.tv_sec)));
  str[24]=0x0;
  va_start(ap,f);
  fprintf(s,"[%s] ",str);
  vfprintf(s,f,ap);
  fflush(s);
  va_end(ap);
}
//
int main(int argc, char *argv[]){
  // 1 key
  // 2 logfile
  size_t const locpos=8+8+16+16;
  size_t const hdrsz=8+8+16+16+8+8;
  unsigned int const BUFSZ=1024;
  unsigned char buf[BUFSZ];
  size_t const LISTSZMAX=4*1024*1024*1024UL; // must be power of 2
  size_t const DATASZMAX=LISTSZMAX+hdrsz;
  size_t const LISTSZMSK=LISTSZMAX-1;
  /*
    | DATASZMAX(8) | HDRSZ(8)     |
    | START TIME(16)              |
    | END TIME(16)                |
    | POINTER(8)   | NULL         |
    | data                        |
   */
  FILE *flog=fopen(argv[2],"a");
  void *endLoc;
  key_t shmkey=ftok(argv[1],0);
  int shmflag=0666|IPC_CREAT;
  int shmid=shmget(shmkey,DATASZMAX,shmflag);
  size_t p;  // pos
  size_t np; // normalized pos
  ssize_t n; // read byte
  size_t ep; // end pos

  t0=getTime();

  if(shmid==-1){
    plog(flog,"shmget: %s\n",strerror(errno));
    exit(1);
  }
  shmdata =  shmat ( shmid, ( void * ) 0, 0 );

  if(shmdata==(void *)-1){
    plog(flog,"shmat: %s\n",strerror(errno));
    exit(1);
  }

  signal(SIGINT,closeShm);
  signal(SIGTERM,closeShm);

  bzero(shmdata,hdrsz);
  memcpy(shmdata,&DATASZMAX,8);
  memcpy(shmdata+8,&hdrsz,8);
  memcpy(shmdata+8+8,&t0,16);

  p=0;
  endLoc=shmdata+locpos;
  memcpy(endLoc,&p,8);
  
  listdata = shmdata + hdrsz;
  plog(flog,"start: shmid=%d, size=%ld\n",shmid,DATASZMAX);  
  do{
    n=read(0,&buf,BUFSZ);
    if(n>0){
      np=p&LISTSZMSK;
      ep=np+(size_t)n;
      if(ep>=LISTSZMAX){
	memcpy(listdata+np,&buf,ep-LISTSZMAX);
	memcpy(listdata,&buf[ep-LISTSZMAX],n-(ep-LISTSZMAX));
      }else{
	memcpy(listdata+np,&buf,n);
      }
      p+=n;
      memcpy(endLoc,&p,8);
    }else{
      break;
    }
  }while(feof(stdin)==0);
  closeShm();
  plog(flog,"Connection closed. recvd = %lu in %lu sec\n",p,t1.tv_sec-t0.tv_sec);
  if(flog!=NULL) fclose(flog);
  exit(0);
}
